%{ 
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include "Automatas.h"
#include "lex.yy.h"
#include <fstream>
#include "NFAtoDFA.h"
#include <cassert>
#include <tr1/memory>

using namespace std;
using namespace tr1;

#define YYDEBUG 1

using namespace std;

extern int yylex();
NondeterministicFiniteAutomaton* nfa;

// better error reporting
#define YYERROR_VERBOSE

void yyerror(const char *msg)
{
      cerr << "ERROR(PARSER): " << msg << endl;
}

%}

%union{
        char val;
	NondeterministicFiniteAutomaton* nfa;
}

%token <val> CARACTER

%left '|'
%nonassoc CARACTER '.'
%nonassoc '('
%left CONCAT 
%nonassoc '+' '*' '?'
%nonassoc PARENTESIS

%type <nfa> exp regexp

%%
regexp: exp								{$$ = $1; nfa = $$;}
exp:	exp exp	%prec CONCAT			{$$ = $1->concat($2);}
		| exp '|' exp					{$$ = $1->o($3);}
		| exp '*'						{$$ = $1->kleeneClosure();}
		| exp '+'						{$$ = $1->positiveClosure();}
		| exp '?'						{$$ = $1->withOptionalOperand();}
		| '(' exp ')' %prec PARENTESIS	{$$ = $2 }
		| CARACTER		{$$ = NondeterministicFiniteAutomaton::acceptingChar($1);}
		| '.'			{$$ = NondeterministicFiniteAutomaton::acceptingDot();}
		;

%%

using namespace std;
YY_BUFFER_STATE yy_scan_string(const char *str);

void matchContentsOfFile(ifstream& file);

//---------------------------------------------------------------
shared_ptr<DeterministicFiniteAutomaton> toDFA(shared_ptr<NondeterministicFiniteAutomaton> nfa)
{
    return NFAtoDFAConversion(nfa).getDfa();
}

int main(int argc, char** argv)
{

    if (argc != 3)
    {
        cout << "El formato del programa es ./exp <REGEXP> <FILENAME>" << endl;
        return -1;
    }
    
    string regexp = argv[1];
    string filename = argv[2];
    /// Open the file
    
    ifstream file(filename.c_str());
    
    if (!file.is_open())
    {
        cout << "El archivo "<< filename << " es inexistente" << endl;
        return -1;
    }
    
    /// Parse the regexp and get the NFA
    yy_scan_string(regexp.c_str());
    yyparse();
    yylex_destroy();

    
    matchContentsOfFile(file);
}

void matchContentsOfFile(ifstream& file)
{
    string line;
    shared_ptr<DeterministicFiniteAutomaton> dfa(toDFA(shared_ptr<NondeterministicFiniteAutomaton>(nfa)));
    
    while (getline(file, line))
    {
        if (dfa->recognize(line))
        {
            cout << line  << endl;
        }
    }
}

